package com.gitee.ly.openfeign;

import com.gitee.ly.DiscoverAndLoadBalancer;
import com.gitee.ly.LightRegistryProperties;
import com.gitee.ly.model.ServiceInfo;
import feign.Client;
import feign.Request;
import feign.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.net.URI;

@Slf4j
public class LightRegistryFeignClient implements Client {

    private final BeanFactory beanFactory;
    private final Client delegate;
    private DiscoverAndLoadBalancer discoverAndLoadBalancer;
    private LightRegistryProperties lightRegistryProperties;
    private LightRegistryFeignClientFinalRequestHandle lightRegistryFeignClientFinalRequestHandle;

    public LightRegistryFeignClient(Client delegate, BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        this.delegate = delegate;
        this.discoverAndLoadBalancer = this.beanFactory.getBean(DiscoverAndLoadBalancer.class);
        this.lightRegistryProperties = this.beanFactory.getBean(LightRegistryProperties.class);
        try {
            this.lightRegistryFeignClientFinalRequestHandle = this.beanFactory.getBean(LightRegistryFeignClientFinalRequestHandle.class);
        } catch (Exception e) {
            log.info("LightRegistryFeignClientFinalRequestHandle no provider");
        }
    }

    @Override
    public Response execute(Request request, Request.Options options) throws IOException {
        Request newRequest = request;
        if (!this.lightRegistryProperties.isEnable()) {
            //没有启用服务中心，走固定Url模式
        } else {
            //启用服务中心，即使有url(会报错)，也走动态模式
            //http://serviceName/pathxxx/xxx/xxx
            URI oldUri = URI.create(request.url());
            String serviceName = oldUri.getHost();
            ServiceInfo serviceInfo = this.discoverAndLoadBalancer.chooseOne(serviceName);
            if (serviceInfo == null) {
                throw new RuntimeException(String.format("Light-Registry serviceName：[%s] NO Find Provider", serviceName));
            }
            boolean encoded = containsEncodedParts(oldUri);
            URI newUri = UriComponentsBuilder.fromUri(oldUri)
                    .scheme(serviceInfo.getSchema())
                    .host(serviceInfo.getIp())
                    .port(serviceInfo.getPort())
                    .build(encoded)
                    .toUri();
            log.info(String.format("Light-Registry serviceLoadBalance：[%s] (transfer to ->) %s ", oldUri, newUri));
            newRequest = Request.create(request.method(), newUri.toString(), request.headers(),
                    request.body(), request.charset());
        }
        //兼容seata的RPC  xxx的RPC请求......自行处理
        if (this.lightRegistryFeignClientFinalRequestHandle != null) {
            newRequest = this.lightRegistryFeignClientFinalRequestHandle.getFinalRequest(newRequest);
        }
        return this.delegate.execute(newRequest, options);
    }

    private static boolean containsEncodedParts(URI uri) {
        boolean encoded = uri.getRawQuery() != null && uri.getRawQuery().contains("%") || uri.getRawPath() != null && uri.getRawPath().contains("%") || uri.getRawFragment() != null && uri.getRawFragment().contains("%");
        if (encoded) {
            try {
                UriComponentsBuilder.fromUri(uri).build(true);
                return true;
            } catch (IllegalArgumentException var3) {
                return false;
            }
        } else {
            return false;
        }
    }
}
